package com.dlc.apk.core

import com.dlc.apk.core.DeviceManager
import com.dlc.hardwareprotocol.serialport.MainSerialManager
import com.dlc.hardwareprotocol.serialport.command.recv.*
import com.dlc.hardwareprotocol.serialport.utils.ByteUtil
import com.dlc.apk.api.ApiConstants
import com.dlc.apk.utils.CacheHelper
import com.dlc.apk.utils.LogPlus
import com.jeremyliao.liveeventbus.LiveEventBus
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import java.util.concurrent.*

class DeviceSerialManager private constructor() {
    var deviceMainSerialManager: MainSerialManager? = null
    private var lastReceivedWorkStatusDataTime: Long = 0

    /**
     * Nthreads=CPU数量
     * Ucpu=目标CPU的使用率，0<=Ucpu<=1
     * W/C=任务等待时间与任务计算时间的比率
     *  Nthreads = Ncpu*Ucpu*(1+W/C)
     */

    private val threadPoolExecutor = ThreadPoolExecutor(8, 20, 1000, TimeUnit.MILLISECONDS, ArrayBlockingQueue<Runnable>(5), object : ThreadFactory {
        override fun newThread(r: Runnable?): Thread {
            return Thread(r, """threadPool${r.hashCode()}""")
        }
    })

    fun init() {
        var serialPortPath = ""
        var serialPortBaudRate = 0

        serialPortPath = CacheHelper.getSerialPortPath()
        serialPortBaudRate = CacheHelper.getSerialPortBaudRate()
        deviceMainSerialManager = openSerialPort(serialPortPath, serialPortBaudRate)
    }

    private fun openSerialPort(serialPortPath: String, baudRate: Int): MainSerialManager {
        val mainSerialManager = MainSerialManager()
        mainSerialManager.initDevice(serialPortPath, baudRate, object : MainSerialManager.SerialOpenCallBack {
            override fun onSuccess() {
                LogPlus.e("###串口打开成功 path->${serialPortPath}")

                mainSerialManager.setReceiveCallback {
                    if (it.allPack == null || it.allPack.isEmpty()) {
                        return@setReceiveCallback
                    }
                    when (it) {
                        is RecvBA -> {
                            //控制板工作状态数据
                            LiveEventBus.get(ApiConstants.EVENT_HARDWARE_WORK_DATA_UPDATED).post(it)
                            lastReceivedWorkStatusDataTime = System.currentTimeMillis()
                            threadPoolExecutor.execute {
                                handleHardwareWorkStatusData(it)
                            }
                            //回复控制板
                            //deviceMainSerialManager?.sendA3Response()
                            LogPlus.e("###BA->${ByteUtil.bytes2HexStr(it.allPack)}")
                        }
                    }
                }

                //定时查询控制板工作状态数据 BA(经测试发现测试设备是每30s自动上传一次,不适用)
                startQueryWorkStatusDataLoop()
            }

            override fun onFailure() {
                LogPlus.e("###串口打开失败 path->${serialPortPath}")
            }
        })
        return mainSerialManager
    }

    /**
     * 处理硬件工作状态数据
     */
    private fun handleHardwareWorkStatusData(workStatusData: RecvBA) {
        //更新MQTT中待发硬件心跳数据
        MQTTClient.workStatusData = workStatusData
        LogPlus.e("###最新设备工作状态数据->${MQTTClient.workStatusData}")
        //更新出货任务进度
        DeviceManager.instance.updateTaskState(workStatusData.flowNo, workStatusData.shipmentState, workStatusData.currentStep, workStatusData.errCode, workStatusData.th1ShipmentResult, workStatusData.th2ShipmentResult, workStatusData.th3ShipmentResult, workStatusData.th4ShipmentResult, workStatusData.th5ShipmentResult)
    }


    private var startQueryWorkStatusDataLoopDisposable: Disposable? = null

    /**
     * 定时查询控制板工作状态数据 BA
     */
    private fun startQueryWorkStatusDataLoop() {
        startQueryWorkStatusDataLoopDisposable?.dispose()
        startQueryWorkStatusDataLoopDisposable = io.reactivex.Observable.interval(5, 2, TimeUnit.SECONDS)
            .subscribeOn(Schedulers.computation())
            .doOnSubscribe { } //执行计时任务前
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe {
                deviceMainSerialManager?.sendBA()
            }
    }

    /**
     * 检查最终出货结果是否成功
     * @param errCode 错误代码 说明：错误代码大于0x80，说明发生了影响出货结果的错误，小于0x80表示没有发生影响出货结果的错误
     * @param shipmentResult 货道掉货结果  大于等于0x03: 掉货成功，掉货数量为此值减去0x02 此货道掉货结果表示相应货道货物是否已经掉下，客户能不能拿到货还需要根据错误代码进行判断。
     */
    fun isShipmentSuccess(errCode: Int, shipmentResult: Int): Boolean {
        val isSuccess = errCode < 0x80 && shipmentResult >= 0x03
        LogPlus.e("###裁定出货结果 errCode->$errCode,shipmentResult->$shipmentResult,result->$isSuccess")
        return isSuccess
    }

    private object InstanceHolder {
        val instance = DeviceSerialManager()
    }

    companion object {
        val instance: DeviceSerialManager
            get() = InstanceHolder.instance
    }
}